package org.tio.showcase.dbUtil;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.mongodb.*;
import com.mongodb.MongoClient;
import com.mongodb.client.*;
import com.mongodb.client.model.Filters;
import com.mongodb.client.result.DeleteResult;
import org.bson.Document;
import org.bson.conversions.Bson;
import org.bson.types.ObjectId;

import java.lang.reflect.Field;
import java.util.*;
import java.util.regex.Pattern;

import static com.mongodb.client.model.Filters.eq;

/**
 * <!--MongoDB 连接依赖-->
 * <dependency>
 * <groupId>org.mongodb</groupId>
 * <artifactId>mongo-java-driver</artifactId>
 * </dependency>
 */
public class MongodbUtil {

    public static final String IP = "localhost";
    public static final int PROT = 27017;
    public static final String USERNAME = "";
    public static final String PASSWORD = "";
    public static final String DATABASE_NAME = "chat";
    private static MongoClient mongoClient;

    // 获取连接
    public static MongoDatabase getAuthConnect(String databaseName) {
        // 连接到 mongodb 服务
        mongoClient = new MongoClient(IP, PROT);
        // 连接到数据库
        MongoDatabase mongoDatabase = mongoClient.getDatabase(databaseName);
        System.out.println("Connect to database successfully");
        return mongoDatabase;
    }

    /**
     * 关闭Mongodb
     */
    public static void close() {
        if (mongoClient != null) {
            mongoClient.close();
            mongoClient = null;
        }
    }
    // 三个参数分别为 用户名  密码  数据库名称
    public static MongoDatabase getAuthConnect(String username, String password, String databaseName) {
        ServerAddress serverAddress = new ServerAddress(IP, PROT);
        List<ServerAddress> addrs = new ArrayList<ServerAddress>();
        addrs.add(serverAddress);

        //MongoCredential.createScramSha1Credential()三个参数分别为 用户名 数据库名称 密码
        MongoCredential credential = MongoCredential.createScramSha1Credential(username, databaseName, password.toCharArray());
        List<MongoCredential> credentials = new ArrayList<MongoCredential>();
        credentials.add(credential);

        //通过连接认证获取MongoDB连接
        mongoClient = new MongoClient(addrs, credentials);

        //连接到数据库
        MongoDatabase mongoDatabase = mongoClient.getDatabase(databaseName);
        return mongoDatabase;
    }

    public static MongoDatabase getAuthConnect() {
        return getAuthConnect(DATABASE_NAME);
    }

    // 创建数据集合（类似mysql 的数据表）
    public static void createDataBase() {
        getAuthConnect().createCollection("test2");
        System.out.println("集合创建成功");
    }

    // 获取集合
    public static MongoCollection<Document> getCollection(String c) {
        // 获取集合，获取
        MongoCollection<Document> collection = getAuthConnect().getCollection(c);
        System.out.println("集合获取成功");
        return collection;
    }



    /**
     * 插入数据，并返回数据ID
     *
     * @param map
     * @return
     */
    public static String addDataBase(String collection, Map map) {
        Document document = new Document(map);
        List<Document> list = new ArrayList<Document>();
        list.add(document);
        getCollection(collection).insertMany(list);
        ObjectId id = (ObjectId) document.get("_id");
        close();
        return id + "";
    }

    public static List addDataBase(String collection, List<Map<String, Object>> list) {
        MongoCollection mongoCollection = getCollection(collection);
        List listId = new ArrayList();
        for (Map map : list) {
            Document document = new Document(map);
            List<Document> addlist = new ArrayList<Document>();
            addlist.add(document);
            mongoCollection.insertMany(addlist);
            ObjectId id = (ObjectId) document.get("_id");
            listId.add(id + "");
        }
        close();
        return listId;
    }



    /**
     * 分页，条件查询（查询条件仅限 String 类型，且 标准 键值对）
     * @param coll
     * @param pageNo
     * @param pageSize
     * @param map
     * @return
     */
    public static List<Object> findByPage(String coll, int pageNo, int pageSize,Map<String,Object> map) {
        // 对所有结果使用阻塞回调方法
        List<Object> list = new ArrayList<>();
        if(map.size() > 0){
            BasicDBObject cond = new BasicDBObject();
            for (String key:map.keySet()) {
                Object val = map.get(key);
                if(val != null){
//                    cond.put(""+key+"", Pattern.compile("^.*" + ""+val+"" + ".*$"));
                    cond.put(""+key+"", Pattern.compile(""+val+""));
                }

            }
            getCollection(coll).find(cond).skip((pageNo - 1) * pageSize).limit(pageSize).forEach((Block<Document>) document -> {
                List<Object> o = Collections.singletonList(document.toJson());
                for (Object ob : o) {
                    list.add(ob);
                }
            });
        }else{
            Bson orderBy = new BasicDBObject("_id", 1);
            getCollection(coll).find().sort(orderBy).skip((pageNo - 1) * pageSize).limit(pageSize).forEach((Block<Document>) document -> {
                List<Object> o = Collections.singletonList(document.toJson());
                for (Object ob : o) {
                    list.add(ob);
                }
            });
        }
        close();
        return list;
    }


    /**
     * 根据 OBjectID 修改，更新数据
     * @param coll
     * @param id
     * @param newdoc
     * @return
     */
    public static Document updateById(String coll, String id, Document newdoc) {
        ObjectId _idobj = null;
        try {
            _idobj = new ObjectId(id);
        } catch (Exception e) {
            return null;
        }
        Bson filter = Filters.eq("_id", _idobj);
        //getCollection(coll).replaceOne(filter, newdoc); // 完全替代
        getCollection(coll).updateOne(filter, new Document("$set", newdoc));
        close();
        return newdoc;
    }

    /**
     * 删除指定数据库下面的指定表
     * @param dbName        数据库
     * @param collName      要删除数据表
     */
    public static void dropCollection(String dbName, String collName) {
        getAuthConnect(dbName).getCollection(collName).drop();
        close();
    }


    /**
     * 统计表数据量
     * @param c
     * @return
     */
    public static int getCount(String c) {
        int count = (int) getCollection(c).count();
        close();
        return count;
    }

    /**
     * 根据 ID 删除
     *
     * @param collection
     * @param id
     * @return
     */
    public static int deleteId(String collection, String id) {
        int count = 0;
        ObjectId _id = null;
        try {
            _id = new ObjectId(id);
        } catch (Exception e) {
            return 0;
        }
        Bson filter = Filters.eq("_id", _id);
        DeleteResult deleteResult = getCollection(collection).deleteOne(filter);
        count = (int) deleteResult.getDeletedCount();
        close();
        return count;
    }

    /**
     * c
     * 使用_id 获取数据
     *
     * @param id
     * @return
     */
    public static List findDocumentById(String collection, String id) {
        BasicDBObject query = new BasicDBObject();
        query.put("_id", new ObjectId(id));
        List list = new ArrayList();
        getCollection(collection).find(query).forEach((Block<Document>) document -> {
            List<Object> o = Collections.singletonList(document.toJson());
            String s = document.toJson();
            for (Object user : o) {
                list.add(user);
            }
        });
        close();
        return list;
    }
    public static List findDocumentById(String collection, List<String> list) {
        MongoCollection mongoCollection = getCollection(collection);
        List<Object> resList = new ArrayList<>();
        for (String id:list) {
            BasicDBObject query = new BasicDBObject();
            query.put("_id", new ObjectId(id));
            mongoCollection.find(query).forEach((Block<Document>) document -> {
                List<Object> o = Collections.singletonList(document.toJson());
                String s = document.toJson();
                for (Object user : o) {
                    resList.add(user);
                }
            });
        }
        close();
        return resList;
    }


    /**
     * 将Object对象里面的属性和值转化成Map对象
     *
     * @param obj
     * @return
     * @throws IllegalAccessException
     */
    public static Map<String, Object> objectToMap(Object obj) throws IllegalAccessException {
        Map<String, Object> map = new HashMap<String, Object>();
       if(obj != null){
           Class<?> clazz = obj.getClass();
           for (Field field : clazz.getDeclaredFields()) {
               field.setAccessible(true);
               String fieldName = field.getName();
               Object value = field.get(obj);
               map.put(fieldName, value);
           }
           close();
       }
        return map;
    }

    /**
     * 获取 _id
     *
     * @param s
     * @return
     */
    public static String getObjectId(Object s) {
        String s1 = JSON.parseObject(s + "").getString("_id");
        return JSON.parseObject(s1).getString("$oid");
    }

    public static void main(String args[]) {
        // 指定的数据表名
        String collection = "user";
        // 指定的数据库名
        String database = "chat";

        try {

            // 分页查询
            /*User u = new User();
            u.setLoginname("好");
            u.setId(1);

            List<Object> list = findByPage(collection,3,5,objectToMap(u));
            for (Object str:list) {
                System.out.println(str);
            }*/
            /*SysUser sysUser = new SysUser();
            sysUser.setUsername("admin9");
            sysUser.setPassword("001");
            List<Object> list = findByPage(collection,0,1,objectToMap(sysUser));
            for (Object str:list) {
                System.out.println(str);
            }*/


            // 根据ID 修改某列数据
            /*Document doc = new Document();
            List<Object> list = new ArrayList<Object>();
            User jg = new User();
            jg.setNick("99");
            jg.setId(2);
            jg.setLoginname("99");
            jg.setIp("99");
            UserInfo jg2 = new UserInfo();
            jg2.setAvatarUrl("999");
            jg2.setPassword("99");
            jg2.setUserId("ras99dr");
            list.add(jg);
            list.add(jg2);
            doc.put("id", JSON.toJSON(list));
            updateById(collection, "5de09750308f6705309e75b0", doc);*/



            // 删除指定数据库下面指定的数据表
            /*dropCollection(database,"test2");*/

            // 统计表的数据量
            /*System.out.println(getCount(collection));*/

            // 根据ID删除
            /*deleteId(collection, "5de09750308f6705309e75b1");*/

            // 批量新增
           /* List<Map<String,Object>> list = new ArrayList<>();
            for (int i = 1; i <= 9; i++) {
                *//*SysUser sysUser = new SysUser();
                sysUser.setUsername("admin"+i);
                sysUser.setPassword("00"+i);
                sysUser.setNick("我是第"+i+"号用户");
                sysUser.setPhone("18877779702");
                sysUser.setSex("男");
                sysUser.setPicUrl("./img/avatar/Member00"+i+".jpg");
                sysUser.setCreationTime(System.currentTimeMillis()+"");*//*
                GroupUser group = new GroupUser();
                group.setGroupId("5de479edd381262ad8ae9f32");
                group.setUserId("admin1");
                group.setCreationTime(System.currentTimeMillis()+"");
                group.setType("1");
                list.add(objectToMap(group));

            }
            System.out.println(addDataBase(collection,list));*/

            // 使用 _ID 获取数据示例
            /*List list = new ArrayList();
            list.add("5de478a04e394c5cdb47f220");
            list.add("5de478a04e394c5cdb47f221");
            list.add("5de478a04e394c5cdb47f222");
            list =  findDocumentById(collection,list);
            for (Object s: list) {
                System.out.println(JSON.parseObject(s+""));
                System.out.println(getObjectId(s));
            }*/


            System.out.println(objectToMap(null));

        } catch (Exception e) {
            System.err.println(e.getClass().getName() + ": " + e.getMessage());
        }
    }
}